%{
#include <stdio.h>
#define YYDEBUG 1
%}

%union{
    char                identifier;
    PackageName         package_name;
    ParameterList       parameter_list;
    ArgumentList        argument_list;
    Expression          expression;
    ExpressionList      expression_list;
    Statement           statement;
    StatementList       statement_list;
    Block               block;
    Elsif               elsif;
    CaseList            case_list;
    AssignmentOperator  assignment_operator;
    FunctionDefinition  function_definition;
    IdentifierList      identifier_list;
}

%token <expression>     INT_LITERAL
%token <expression>     DOUBLE_LITERAL
%token <expression>     STRING_LITERAL
%token <expression>     REGEXP_LITERAL
%token <identifier>     IDENTIFIER
%token <identifier>     GLOBAL
%token FUNCTION IF ELSE ELSIF SWITCH CASE DEFAULT_T WHILE DO FOR IN RETURN_T BREAK CONTINUE NULL_T
        LP RP LC RC LB RB SEMICOLON COLON COMMA ASSIGN_T LOGICAL_AND LOGICAL_OR
        EQ NE GT GE LT LE ADD SUB MUL DIV MOD BIT_AND BIT_OR BIT_XOR BIT_NOT BIT_XOR_ASSIGN_T
        TRUE_T FALSE_T EXCLAMATION DOT IS IMPORT AS BIT_AND_ASSIGN_T DOT_MUL DOT_DIV
        ADD_ASSIGN_T SUB_ASSIGN_T MUL_ASSIGN_T DIV_ASSIGN_T MOD_ASSIGN_T BIT_OR_ASSIGN_T
        INCREMENT DECREMENT TRY CATCH FINALLY CONST
%type   <package_name> package_name
%type   <parameter_list> parameter_list
%type   <argument_list> argument_list
%type   <expression> expression expression_opt
        assignment_expression logical_and_expression logical_or_expression
        equality_expression relational_expression
        additive_expression multiplicative_expression
        unary_expression postfix_expression primary_expression array_literal
%type   <expression_list> expression_list
%type   <statement> statement if_statement while_statement for_statement
        return_statement break_statement continue_statement try_statement
        const_statement  switch_statement do_while_statement
%type   <statement_list> statement_list
%type   <block> block
%type   <elsif> elsif elsif_list
%type   <case_list> case_list one_case
%type   <assignment_operator> assignment_operator
%type   <identifier_list> identifier_list identifier1
%%
translation_unit
        : initial_declaration definition_or_statement
        | translation_unit definition_or_statement
        ;
initial_declaration
        : /* empty */
        {}
        | IMPORT package_name SEMICOLON
        {}
        | IMPORT package_name AS IDENTIFIER SEMICOLON
        {}
        ;
package_name
        :STRING_LITERAL
        {}
        ;
definition_or_statement
        : function_definition
        | statement
        {}
        ;
function_definition
        : FUNCTION IDENTIFIER LP parameter_list RP block
        {}
        | FUNCTION IDENTIFIER LP RP block
        {}
        ;
parameter_list
        : IDENTIFIER
        {}
        | parameter_list COMMA IDENTIFIER
        {}
        ;
argument_list
        : assignment_expression
        {}
        | argument_list COMMA assignment_expression
        {}
        ;
statement_list
        : statement
        {}
        | statement_list statement
        {}
        ;
expression
        :assignment_expression
        | expression COMMA assignment_expression
        {}
        ;
assignment_expression
        : logical_or_expression
        | postfix_expression assignment_operator assignment_expression
        {}
        ;
assignment_operator
        : ASSIGN_T
        {}
        | ADD_ASSIGN_T
        {}
        | SUB_ASSIGN_T
        {}
        | MUL_ASSIGN_T
        {}
        | DIV_ASSIGN_T
        {}
        | MOD_ASSIGN_T
        {}
        | BIT_XOR_ASSIGN_T
        {}
        | BIT_AND_ASSIGN_T
        {}
        | BIT_OR_ASSIGN_T
        {}
        ;
logical_or_expression
         : logical_and_expression
         | logical_or_expression LOGICAL_OR logical_and_expression
         {}
         ;
logical_and_expression
        : equality_expression
        | logical_and_expression LOGICAL_AND equality_expression
        {}
        ;
equality_expression
        : relational_expression
        | equality_expression EQ relational_expression
        {}
        | equality_expression NE relational_expression
        {}
        ;
relational_expression
        : additive_expression
        | relational_expression GT additive_expression
        {}
        | relational_expression GE additive_expression
        {}
        | relational_expression LT additive_expression
        {}
        | relational_expression LE additive_expression
        {}
        ;
additive_expression
        : multiplicative_expression
        | additive_expression ADD multiplicative_expression
        {}
        | additive_expression SUB multiplicative_expression
        {}
        ;
multiplicative_expression
        : unary_expression
        | multiplicative_expression MUL unary_expression
        {}
        | multiplicative_expression DIV unary_expression
        {}
        | multiplicative_expression MOD unary_expression
        {}
        | multiplicative_expression DOT_MUL unary_expression
        {}
        | multiplicative_expression DOT_DIV unary_expression
        {}
        | multiplicative_expression BIT_AND unary_expression
        {}
        | multiplicative_expression BIT_OR unary_expression
        {}
        | multiplicative_expression BIT_XOR unary_expression
        {}
        ;
unary_expression
        : postfix_expression
        | SUB unary_expression
        {}
        | EXCLAMATION unary_expression
        {}
        | BIT_NOT unary_expression
        {}
        ;
postfix_expression
        : primary_expression
        | primary_expression INCREMENT
        {}
        | primary_expression DECREMENT
        {}
        | postfix_expression LB expression RB
        {}
        | postfix_expression DOT IDENTIFIER
        {}
        | postfix_expression LP argument_list RP
        {}
        | postfix_expression LP RP
        {}
        ;
primary_expression
        : LP expression RP
        {}
        | IDENTIFIER
        {}
        | INT_LITERAL
        | DOUBLE_LITERAL
        | STRING_LITERAL
        | REGEXP_LITERAL
        | TRUE_T
        {}
        | FALSE_T
        {}
        | NULL_T
        {}
        | array_literal
        | GLOBAL
        {}
        ;
array_literal
        : LB expression_list RB
        {}
        | LB expression_list COMMA RB
        {}
        ;
expression_list
        : /* empty */
        {}
        | assignment_expression
        {}
        | expression_list COMMA assignment_expression
        {}
        ;
statement
        : expression SEMICOLON
        {}
        | if_statement
        | while_statement
        | do_while_statement
        | switch_statement
        | for_statement
        | return_statement
        | break_statement
        | continue_statement
        | try_statement
        | const_statement
        ;
const_statement
        : CONST identifier_list SEMICOLON
        {}
        ;
identifier_list
        : identifier1
        | identifier_list COMMA identifier1
        {}
        ;
identifier1
        : IDENTIFIER ASSIGN_T identifier2
        {}
        ;
identifier2
        : INT_LITERAL
         | DOUBLE_LITERAL
         | STRING_LITERAL
         | TRUE_T
         {}
         | FALSE_T
         {}
         | NULL_T
         {}
         | array_literal
if_statement
        : IF LP expression RP block
        {}
        | IF LP expression RP block ELSE block
        {}
        | IF LP expression RP block elsif_list
        {}
        | IF LP expression RP block elsif_list ELSE block
        {}
        ;
elsif_list
        : elsif
        | elsif_list elsif
        {}
        ;
elsif
        : ELSIF LP expression RP block
        {}
        ;
while_statement
        : WHILE LP expression RP block
        {}
        ;
do_while_statement
        : DO block WHILE LP expression RP SEMICOLON
        {}
        ;
switch_statement
        : SWITCH LP expression RP case_list default_opt
        {}
        ;
case_list
        : one_case
        | case_list one_case
        {}
        ;
one_case
        : CASE case_expression_list block
        {}
        ;
default_opt
        : /* empty */
        {}
        | DEFAULT_T block
        {}
        ;
case_expression_list
        : assignment_expression
        {}
        | expression_list COMMA assignment_expression
        {}
        ;
for_statement
        : FOR LP expression_opt SEMICOLON expression_opt SEMICOLON
          expression_opt RP block
        {}
        ;
expression_opt
        : /* empty */
        {
            $$ = NULL;
        }
        | expression
        ;
return_statement
        : RETURN_T expression_opt SEMICOLON
        {}
        ;
break_statement
        : BREAK SEMICOLON
        {}
        ;
continue_statement
        : CONTINUE  SEMICOLON
        {}
        ;
try_statement
        : TRY block CATCH LP IDENTIFIER RP block FINALLY block
        {}
        | TRY block CATCH LP IDENTIFIER RP block
        {}
block
        : LC statement_list RC
        {}
        | LC RC
        {}
        ;
%%